/**
    ATClab - scriptable Air Traffic Control simulations.
    Copyright (C) 2010 openatclab@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#ifndef __ATC_UICOMPONENT_HDR__
#define __ATC_UICOMPONENT_HDR__

#include <q3frame.h>
#include <qlayout.h>
//Added by qt3to4:
#include <Q3GridLayout>
#include <QShowEvent>
#include <QLabel>
#include <QKeyEvent>
#include "logging\logger.h"
#include <vector>
#include <string>

//Qt
class QButtonGroup;
class QLabel;
class QLineEdit;
class QPushButton;
class QValidator;


namespace pact {

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/*!
	 * \struct pact::uicomponent_error
	 */
	struct uicomponent_error : public std::runtime_error{
		uicomponent_error(const std::string& msg) : std::runtime_error(msg) {}
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/*!
	 *
	 */
	class Question : public Q3Frame {
		Q_OBJECT
	public:
		Question( QWidget *p, const std::string &name ) : Q3Frame( p, name.c_str() ) {}
		~Question() {}
	public:
		virtual void construct() = 0;
	signals:
		void accepted();
		void sig_data(logging::KVPairs &);
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/*!
	 * \class pact::BaseQuestion
	 */
	class BaseQuestion : public Question {
		Q_OBJECT
	public:
		BaseQuestion( QWidget *, const std::string & );
		virtual ~BaseQuestion();
		void set_text(	const std::string&	text, 
						int					x = -1, 
						int					y = -1);

		void add_label( const std::string & );
		virtual void construct() = 0;
	protected:
		QWidget* construct_text();
		QWidget* construct_labels( int * = 0 );
	protected: // virtual
		virtual void keyPressEvent( QKeyEvent * );
		virtual void showEvent( QShowEvent * );
	protected slots:
		virtual void reset();
		virtual void validate();
		virtual void setAnswer( int );
	signals:
		//void accepted();
	protected:
		std::string _text;
		std::vector< std::string > _labels;
		int m_x;
		int m_y;

	private:
		typedef std::vector< std::string >::const_iterator LabelIt;
	};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	struct ChoiceDetails
	{
		std::string m_text;
		int			m_value;
		std::string m_ref;
		int			m_x;
		int			m_y;
		int			m_w;
		int			m_h;

		const char* c_str() {
			return m_text.c_str();
		}
	};

	/*!
	 *
	 */
	class ChoiceQuestion : public BaseQuestion {
		Q_OBJECT
	public:
		ChoiceQuestion( QWidget *, const std::string & );
		virtual ~ChoiceQuestion();
		void add_choice(const std::string&	a_choice, 
						int					a_value = -1, 
						const std::string&	a_ref = "",
						int					x = -1,
						int					y = -1,
						int					w = -1,
						int					h = -1);

		virtual void construct();
	protected:
		QWidget* construct_buttons( int * = 0 );
	
	protected slots:
		void setAnswer(int a_idx);

	protected:
		std::vector< ChoiceDetails > _choices;
	private:
		typedef std::vector< ChoiceDetails >::iterator ChoiceIt;
	};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/*!
	 * \class pact::BaseScaleQuestion
	 */
	class BaseScaleQuestion : public BaseQuestion {
		Q_OBJECT
	public:
		BaseScaleQuestion( QWidget *, const std::string & );
		virtual ~BaseScaleQuestion();
		void set_scale( int, int );
		virtual void construct() = 0;
	protected:
		QWidget* construct_scale( int * = 0 );
	protected:
		int _scaleMin;
		int _scaleMax;
	};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/*!
	 * \class pact::ScaleQuestion
	 */
	class ScaleQuestion : public BaseScaleQuestion {
		Q_OBJECT
	public:
		ScaleQuestion( QWidget *, const std::string & );
		virtual ~ScaleQuestion();
	public:
		virtual void construct();
	};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	/*!
	 * \class pact::MultiQuestion
	 */
	class MultiQuestion : public BaseScaleQuestion {
		Q_OBJECT
	public:
		MultiQuestion( QWidget *, const std::string & );
		virtual ~MultiQuestion();
		void add_question( const std::string & );
		void set_numbered();
		void set_must_answer();
		virtual void construct();
	protected: // virtual
		virtual void keyPressEvent( QKeyEvent * );
	protected slots:
		virtual void reset();
		virtual void validate();
//		virtual void setAnswer( int );
		virtual void done();
	private:
		std::vector< std::string > _questions;
		bool _isNumbered;
		bool _mustAnswer;
		std::vector<QButtonGroup*> _answers;
		QPushButton *_okBtn;
	private:
		typedef std::vector< std::string >::const_iterator QuestionIt;
		typedef std::vector< QButtonGroup * >::const_iterator AnswerIt;
	};


	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	enum ValidationQuestionType
	{
		VALIDATION_NA,
		VALIDATION_NORMAL,
		VALIDATION_SR_GOAL,
		VALIDATION_NORM_GOAL
	};

	/*!
	 * \class pact::ValidatedQuestion
	 */
	class ValidatedQuestion : public Question {
		Q_OBJECT
	public:
		ValidatedQuestion( QWidget *, const std::string &, ValidationQuestionType type = VALIDATION_NORMAL);
		virtual ~ValidatedQuestion();
	public:
		virtual void construct() {};
	public:
		void set_text( const std::string & );
		void set_validator( QValidator * );
		void set_validator_message( const std::string & );
	protected: //virtual
		virtual void showEvent( QShowEvent * );
		virtual void keyPressEvent( QKeyEvent * );
	protected slots:
		virtual void reset();
		virtual void validate();
//		virtual void setAnswer( int );
		virtual void done();
	signals:
		//void accepted();
		void sig_accepted(int);
	private:
		unsigned short	m_column;
		QLineEdit		*_input;
		QLabel			*_message;
		QPushButton		*_okBtn;
		Q3GridLayout*	m_layout;
		ValidationQuestionType m_type;
	};

	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
};


#endif
